package com.dmpp.captcha;

import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
import java.util.Optional;

/**
 * @Author 北橙
 * @Create 2022/6/13
 * @Description 验证码逻辑
 */
@AllArgsConstructor
public class CaptchaServiceImpl implements CaptchaService {

    private final static String VERIFICATION_CODE_KEY = "VerificationCode";

    private final CaptchaProperties captchaProperties;

    private final RedissonClient redissonClient;

    private final AbstractCaptcha captcha;

    public String getRedisKey(String account, String code) {
        return VERIFICATION_CODE_KEY + ":" + account + ":" + code.toUpperCase();
    }

    public String getRedisKey(String code) {
        return VERIFICATION_CODE_KEY + ":" + code.toUpperCase();
    }

    @Override
    public void getCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
        captcha.createCode();
        String verificationAccount = request.getParameter(captchaProperties.getAccountParamName());
        RBucket<String> bucket;
        if (StrUtil.isNotEmpty(verificationAccount)){
            bucket = redissonClient.getBucket(getRedisKey(verificationAccount, captcha.getCode()));
        }else {
            bucket = redissonClient.getBucket(getRedisKey(captcha.getCode()));
        }
        bucket.set(captcha.getCode(), Duration.ofMinutes(10));
        captcha.write(response.getOutputStream());
    }

    @Override
    public boolean checkCaptcha(String verificationAccount, String verificationCode) {
        if (StrUtil.isEmpty(verificationAccount) || StrUtil.isEmpty(verificationCode)) {
            return false;
        }
        RBucket<String> bucket = redissonClient.getBucket(getRedisKey(verificationAccount, verificationCode));
        String redisCode = Optional.ofNullable(bucket.get()).orElse(StrUtil.EMPTY);
        if (StrUtil.isEmpty(redisCode)) {
            return false;
        }
        if (redisCode.equals(verificationCode)) {
            bucket.delete();
            return true;
        }
        return false;
    }

    @Override
    public boolean checkCaptcha(HttpServletRequest request) {
        String verificationCode = request.getParameter(captchaProperties.getParamName());
        return checkCaptcha(verificationCode);
    }

    @Override
    public boolean checkCaptcha(String verificationCode) {
        if (StrUtil.isEmpty(verificationCode)) {
            return false;
        }
        RBucket<String> bucket = redissonClient.getBucket(getRedisKey(verificationCode));
        String redisCode = bucket.get();
        if (StrUtil.isEmpty(redisCode)) {
            return false;
        }
        if (redisCode.equalsIgnoreCase(verificationCode)) {
            bucket.delete();
            return true;
        }
        return false;
    }
}
